pub fn learn_drop() {
  _learn_drop_example0();
  println!("after example0");
}

struct HasDrop1;
struct HasDrop2;
impl Drop for HasDrop1 {
  fn drop(&mut self){
    println!("Dropping HasDrop1!");
  }
}
impl Drop for HasDrop2 {
  fn drop(&mut self){
    println!("Dropping HasDrop2!");
  }
}
struct HasTwoDrops {
  one: HasDrop1,
  two: HasDrop2,
}
/* 
impl Drop for HasTwoDrops {
  fn drop(&mut self){
    println!("Dropping HasTwoDrops!");
  }
}
*/
#[derive(Debug)]
struct Foo;
impl Drop for Foo {
  fn drop(&mut self){
    println!("Dropping Foo!");
  }
}
fn _learn_drop_example0(){
  let _x = HasTwoDrops{
    two:HasDrop2,
    one:HasDrop1,
  };
  let _foo = Foo;
  println!("Running!");
}

// drop的顺序
// 变量级别,按照逆序的方式, _x在 _foo 之前创建, 因此 _x 在 _foo 之后被drop
// 结构体内部,按照顺序的方式, 结构体 _x 中的字段按照定义中的顺序依次 drop

// 没有实现Drop的结构体
// 内部字段依然会调用Drop,且依然按结构体字段定义的顺序依次drop
// 因为rust自动为几乎所有类型实现了Drop特征

// 手动回收
// 使用智能指针管理锁的时候,可能希望提前释放锁,然后让其他代码能及时获得锁,此时就需要
// 提前手动drop. 但有个疑问, Drop::drop只是借用了目标值的可变引用,所以,就算你
// 提前调用了drop,后面的代码依然可以使用目标值,但是这就会访问一个并不存在的值,
// 非常不安全. 好在rust会阻止这样做.
fn _learn_drop_example1(){
  let foo = Foo;
  // foo.drop(); // 不允许显式地调用析构函数,建议使用drop函数: drop(foo)
  drop(foo); // pub fn drop<T>(_x:T) // 拿走了所有权
  // println!("Running!:{:?}", foo); // 报错:借用了所有权被转移的值
}

// Drop使用场景
// 回收内存资源
// 执行一些收尾工作
// 绝大多数情况下,都无需手动drop以回收内存资源,因为rust会自动帮我们完成这些工作,
// 它甚至会对复杂类型的每个字段都单独的调用drop进行回收!但是确实有极少数情况,需要
// 你自己来回收资源,如文件描述符,网络socket等,当这些值超出作用域不再使用时,就需要
// 进行关闭以释放相关的资源,在这些情况下,就需要使用者自己来解决drop的问题.

// 互斥的Copy和Drop
// 我们无法为一个类型同时实现Copy和Drop特征.因为实现了Copy的类型会被编译器隐式
// 的复制,因此非常难以预测析构函数执行的时间和频率.因此实现了Copy的类型无法拥有
// 析构函数

// #[derive(Copy)] //the trait `Copy` cannot be implemented for this type;
//  the type has a destructor `Copy` not allowed on types with destructors 
struct Foo2;
impl Drop for Foo2{
  fn drop(&mut self){
    println!("Dropping Foo!");
  }
}